//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package tasks

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	bg_runner_core "atomgit.com/openlinksaas/api-server/bg_runner/core"
	"atomgit.com/openlinksaas/api-server/dao/alarm_dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_alarm_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_issue_api"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
)

//单个issue警告级别的告警任务

type IssueDelayCheck struct {
	ProjectId string `json:"projectId"`
	IssueId   string `json:"issueId"`
	AlarmType uint32 `json:"alarmType"`
}

func (t *IssueDelayCheck) TaskType() string {
	return "IssueDelayCheck"
}

func (t *IssueDelayCheck) Execute(logger *zap.Logger) error {
	defer api_common.SendNoticeToProjectScope(context.Background(), t.ProjectId, &notices_project.UpdateAlarmStatNotice{
		ProjectId: t.ProjectId,
	})

	alarmId := fmt.Sprintf("%s:%d", t.IssueId, t.AlarmType)
	configItem, err := alarm_dao.ConfigDao.Get(context.Background(), t.ProjectId)
	if err != nil {
		return alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
	}
	if !configItem.EnableIssueDelayCheck {
		return alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
	}
	exist, err := issue_dao.IssueDao.Exist(context.Background(), t.ProjectId, t.IssueId)
	if err != nil {
		return err
	}
	if !exist {
		return alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
	}
	nowTime := time.Now().UnixNano() / 1e6
	issueItem, err := issue_dao.IssueDao.Get(context.Background(), t.ProjectId, t.IssueId)
	if err != nil {
		return err
	}
	if issueItem.State == int32(project_issue_api.ISSUE_STATE_ISSUE_STATE_CLOSE) {
		return alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
	}
	if issueItem.HasDeadLineTime && issueItem.DeadLineTime < nowTime {
		err = alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
		if err != nil {
			return err
		}
		if t.AlarmType == uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_ALERT) {
			hitAlarmId := fmt.Sprintf("%s:%d", t.IssueId, project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_HIT)
			err = alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, hitAlarmId)
			if err != nil {
				return err
			}
		}
		alarm := &project_alarm_api.Alarm{
			AlarmId:   alarmId,
			ProjectId: t.ProjectId,
			TimeStamp: nowTime,
			AlarmType: project_alarm_api.ALARM_TYPE(t.AlarmType),
			Title:     "",
		}
		if t.AlarmType == uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_HIT) {
			alarm.Content = &project_alarm_api.Alarm_IssueDelayHitInfo{
				IssueDelayHitInfo: &project_alarm_api.IssueDelayHitInfo{
					IssueId:   t.IssueId,
					IssueType: uint32(issueItem.IssueType),
				},
			}
		} else {
			alarm.Content = &project_alarm_api.Alarm_IssueDelayAlertInfo{
				IssueDelayAlertInfo: &project_alarm_api.IssueDelayAlertInfo{
					IssueId:   t.IssueId,
					IssueType: uint32(issueItem.IssueType),
				},
			}
		}
		content, err := proto.Marshal(alarm)
		if err != nil {
			return err
		}
		alarmLevel := uint32(alarm_dao.ALARM_LEVEL_ALERT)
		if t.AlarmType == uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_DELAY_HIT) {
			alarmLevel = alarm_dao.ALARM_LEVEL_HIT
		}
		return alarm_dao.AlarmDao.Insert(context.Background(), &alarm_dao.AlarmDbItem{
			AlarmId:    alarmId,
			ProjectId:  t.ProjectId,
			TimeStamp:  nowTime,
			AlarmType:  t.AlarmType,
			AlarmLevel: alarmLevel,
			Content:    content,
		})
	} else {
		return alarm_dao.AlarmDao.Remove(context.Background(), t.ProjectId, alarmId)
	}
}

func (t *IssueDelayCheck) NewInstance(jsonData []byte) (bg_runner_core.BackGroundTask, error) {
	obj := &IssueDelayCheck{}
	err := json.Unmarshal(jsonData, obj)
	if err != nil {
		return nil, err
	}
	return obj, nil
}
